﻿#include "SerialPort.h"


CSerialPort::CSerialPort()
{
    for(int i = 0; i < 5; i++)
    {
        m_hComm[i] = NULL;
    }
}


CSerialPort::~CSerialPort()
{
    for(int i = 0; i < 5; i++)
    {
        CloseComm(i);
    }
    m_startComm = false;
}

void WINAPI myfun(LPVOID lpParameter)
{
    // TODO: Add your thread code here.
    CSerialPort *window = (CSerialPort*)lpParameter;
    while (window->m_startComm)
    {
        Sleep(20);
        for(int i = 0; i < 5; i++)
        {
            if(window->m_hComm[i] == NULL)
            {
                continue;
            }

            DWORD dwError = 0;
            COMSTAT comStat;
            BOOL bRet = TRUE;
            char recvTemp[512];//临时缓冲区
            ZeroMemory(recvTemp, sizeof(recvTemp));

            char recvBuf[4096];//真正的缓冲区
            ZeroMemory(recvBuf, sizeof(recvBuf));

            DWORD dwRead = 0;
            int nLength = 0;

            ClearCommError(window->m_hComm[i], &dwError, &comStat);
            if (comStat.cbInQue > 0)//判断输入缓存区是否有数据
            {
                OVERLAPPED overlappedRead;
                ZeroMemory(&overlappedRead, sizeof(OVERLAPPED));
                overlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

                if (comStat.cbInQue < 512)
                {
                    bRet = ReadFile(window->m_hComm[i], recvTemp, comStat.cbInQue, &dwRead, &overlappedRead);
                }
                else
                {
                    bRet = ReadFile(window->m_hComm[i], recvTemp, 500, &dwRead, &overlappedRead);
                }

                if (comStat.cbInQue >= dwRead)
                {
                    nLength = 0;
                    memcpy(recvBuf + nLength, recvTemp, dwRead);
                    nLength += dwRead;
                }

                CloseHandle(overlappedRead.hEvent);


                if (comStat.cbInQue == dwRead)
                {
                    nLength = 0;

                    char *p = recvBuf;
                    string strRecv = p;
                    string cut;

                    int num_1 = strRecv.find("02");
                    int num_2 = strRecv.find("0D0A");

                    if(num_1 == -1 || num_2 == -1 || num_2 - num_1 - 2 <= 0)
                    {
                        cut = "";
                    }
                    else
                    {
                         string strcut = strRecv.substr(num_1+2, num_2 - num_1 - 2);
                         string hex1 = "";
                         char *hex = (char*)strcut.data();
                         for (int i = 0; i < strcut.length()-1; i+=2)
                         {
                             hex1 = hex1 + hex[i] + hex[i+1] + " ";
                         }
                         cut = window->Hex2Ascii(hex1);
                    }

                    window->ReceivedPush(i, cut);
                }

//                if (!bRet)//判断是否重叠
//                {
//                    if (ERROR_IO_PENDING == GetLastError())
//                    {
//                        while (!bRet)
//                        {
//                            //bRet = pSerialPort->GetOverlappedResult(NULL, &dwRead, TRUE);
//                            bRet = GetOverlappedResult(window->m_hComm[i], NULL, &dwRead, TRUE);
//                            if (GetLastError() != ERROR_IO_INCOMPLETE)
//                            {
//                                ClearCommError(window->m_hComm[i], &dwError, &comStat);
//                                break;
//                            }
//                        }
//                    }
//                }
            }
        }
    }

}



void CSerialPort::StartComm(int id)
{
    m_startComm = true;
    HANDLE hThread1 = (HANDLE)_beginthread(myfun, 0, this);
}


void CSerialPort::StopComm(int id)
{
    m_startComm = false;
}

BOOL CSerialPort::OpenComm(int id)
{
    char *intStr;
    itoa(id,intStr,10);
    string str = string(intStr);
    string strComm = "COM" + str;
    size_t origsize = strComm.length() + 1;
    const size_t newsize = 100;
    size_t convertedChars = 0;
    wchar_t *wcstring = (wchar_t *)malloc(sizeof(wchar_t)*(strComm.length() - 1));
    mbstowcs_s(&convertedChars, wcstring, origsize, strComm.c_str(), _TRUNCATE);


    if (NULL == m_hComm[id])
	{
        m_hComm[id] = CreateFile(wcstring,//COM口
			GENERIC_READ | GENERIC_WRITE, //允许读和写  
			0, //独占方式  
			NULL,
			OPEN_EXISTING, //打开而不是创建  
			FILE_FLAG_OVERLAPPED, //同步方式  
			NULL);
        if (INVALID_HANDLE_VALUE == m_hComm[id])
		{
			int nError = GetLastError();
            m_hComm[id] = NULL;
            //AfxMessageBox(_T("串口打开失败"));
			return FALSE;
		}
		return TRUE;
	}
	return FALSE;
}

BOOL CSerialPort::SetCommState(int id, DWORD dwBaudrate, BYTE byParity, BYTE byByteSize, BYTE byStopBits)
{
    if (NULL == m_hComm[id]) return FALSE;
	DCB dcb;
    BOOL bRet = ::GetCommState(m_hComm[id], &dcb);
	if (!bRet)
	{
        if (m_hComm[id])
		{
            CloseHandle(m_hComm[id]);
            m_hComm[id] = NULL;
		}
		return FALSE;
	}
	dcb.BaudRate = dwBaudrate;
	dcb.Parity	 = byParity;
	dcb.ByteSize = byByteSize;
	dcb.StopBits = byStopBits;

    bRet = ::SetCommState(m_hComm[id], &dcb);
	if (!bRet)
	{
        if (m_hComm[id])
		{
            CloseHandle(m_hComm[id]);
            m_hComm[id] = NULL;
		}
		return FALSE;
	}
	return TRUE;
}

BOOL CSerialPort::SetupComm(int id, DWORD dwInQueue, DWORD dwOutQueue)
{
    if (NULL == m_hComm[id]) return FALSE;
    return ::SetupComm(m_hComm[id], dwInQueue, dwOutQueue);
}

BOOL CSerialPort::PurgeComm(int id, DWORD dwFlags)
{
    if (NULL == m_hComm[id]) return FALSE;
    return ::PurgeComm(m_hComm[id], dwFlags);
}

BOOL CSerialPort::SetCommMask(int id, DWORD dwEvtNask)
{
    if (NULL == m_hComm[id]) return FALSE;
    return ::SetCommMask(m_hComm[id], dwEvtNask);
}


BOOL CSerialPort::WriteFile(int id, string strsend)
{
    if(m_hComm[id] == NULL)
    {
        return false;
    }

    BOOL bRet = TRUE;
    OVERLAPPED overlappedWrite;
    ZeroMemory(&overlappedWrite, sizeof(OVERLAPPED));
    overlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

    int nLen = (strsend.length() + 1) * sizeof(TCHAR);
    DWORD dwWrite = 0;

    bRet = ::WriteFile(m_hComm[id], (TCHAR*)strsend.c_str(), nLen, &dwWrite, &overlappedWrite);


    CloseHandle(overlappedWrite.hEvent);

    return bRet;

//	if (NULL == m_hComm) return FALSE;
//	return ::WriteFile(m_hComm,lpBuffer, nNumberOfBytesToWrite,lpNumberOfBytesWritten,lpOverlapped);

}


BOOL CSerialPort::ReadFile(int id,
	OUT LPVOID lpBuffer,// 读入的数据存储的地址：即读入的数据将存储在以该指针的值为首地址的一片内存区  
	IN DWORD nNumberOfBytesToRead, // 要读入的数据的字节数  
	OUT LPDWORD lpNumberOfBytesRead,// 指向一个DWORD数值，该数值返回读操作实际读入的字节数  
	IN LPOVERLAPPED lpOverlapped// 重叠操作时，该参数指向一个OVERLAPPED结构，同步操作时，该参数为NULL 
	)
{
    if (NULL == m_hComm[id]){ return FALSE;}
    return ::ReadFile(m_hComm[id],lpBuffer, nNumberOfBytesToRead,lpNumberOfBytesRead,lpOverlapped);
}

BOOL CSerialPort::ClearCommError(int id, OUT LPDWORD lpError, OUT LPCOMSTAT lpStat)
{
    if (NULL == m_hComm[id]) return FALSE;
    return ::ClearCommError(m_hComm[id], lpError, lpStat);
}

BOOL CSerialPort::GetOverlappedResult(int id,
	IN LPOVERLAPPED lpOverlapped,//指向重叠操作开始时指定的OVERLAPPED结构  
	OUT LPDWORD lpNumberOfBytesTransferred,//指向一个32位变量，该变量的值返回实际读写操作传输的字节数。  
	IN BOOL bWait// 该参数用于指定函数是否一直等到重叠操作结束：如果该参数为TRUE，函数直到操作结束才返回；
	//如果该参数为FALSE，函数直接返回，这时如果操作没有完成，通过调用GetLastError()函数会
	//返回ERROR_IO_INCOMPLETE。 
	)
{
    if (NULL == m_hComm[id]) return FALSE;
    return ::GetOverlappedResult(m_hComm[id],lpOverlapped, lpNumberOfBytesTransferred, bWait);
}


void CSerialPort::CloseComm(int id)
{
    //m_hThreadComm.stop();
    if (m_hComm[id] != NULL)
	{
        CloseHandle(m_hComm[id]);
        m_hComm[id] = NULL;
	}
}

//十六进制转字符串
string CSerialPort::Hex2Ascii(string& hexStr)
{
    int asciiLen = 0;
    int hexLen = hexStr.length();
    char *hex = (char*)hexStr.data();
    char ascii[2000];
    for (int i = 0, cnt = 0; i < hexLen; i++)
    {
        uint8_t data = hex[i];
        char c = ((data >= '0') && (data <= '9')) ? int(data - '0') :
            ((data >= 'A') && (data <= 'F')) ? int(data - 'A' + 10) :
            ((data >= 'a') && (data <= 'f')) ? int(data - 'a' + 10) :
            -1;

        if (-1 == c)
            continue;
        if (cnt) {
            cnt = 0;
            ascii[asciiLen++] += c;
        }
        else {
            cnt = 1;
            ascii[asciiLen] = c << 4;
        }
    }
    ascii[asciiLen++] = 0;
    return ascii;
}

//字符串转换程16进制字符串
string CSerialPort::str2Hexstr(string &str)
{
    string hex = "";
    char chars[20] = "0123456789ABCDEF";

    int n;
    for (int i = 0; i < str.length(); i++) {
        int kk = (int)str[i];
        n = (kk & 0xf0) >> 4;
        hex = hex + chars[n];
        n = kk & 0x0f;
        hex = hex + chars[n];
    }
    cout << hex.c_str() << endl;
    return hex;
}

void CSerialPort::ReceivedClear(int id)
{
    m_mutex[id].lock();
    m_Received[id].clear();
    m_mutex[id].unlock();
}

void CSerialPort::ReceivedPush(int id, string str)
{
    m_mutex[id].lock();
    m_Received[id].push_back(str);
    m_mutex[id].unlock();
}

string CSerialPort::ReceivedPop(int id)
{
    string str = "";
    m_mutex[id].lock();
    if(m_Received[id].size()  == 0)
    {
        return str;
    }
    str = m_Received[id].front();
    vector<string>::iterator k = m_Received[id].begin();
    m_Received[id].erase(k);
    m_mutex[id].unlock();
    return str;
}

int CSerialPort::ReceivedSize(int id)
{
    m_mutex[id].lock();
    auto size =  m_Received[id].size();
    m_mutex[id].unlock();
    return  (int)size;
}

